package com.bestcem.xm.member.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.constant.AppRequestErrorCode;
import com.bestcem.xm.common.core.constant.AppResourceErrorCode;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.uitls.EnumUtil;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.member.controller.dto.HttpImportRecordDTO;
import com.bestcem.xm.member.controller.dto.HttpImportRecordDetailDTO;
import com.bestcem.xm.member.controller.dto.HttpRecordProgressDTO;
import com.bestcem.xm.member.controller.v2.param.GetImportProgressQuery;
import com.bestcem.xm.member.controller.v2.param.HttpGetImportRecordParam;
import com.bestcem.xm.member.dao.ImportRecordDao;
import com.bestcem.xm.member.entity.pojo.ImportRecordDo;
import com.bestcem.xm.member.entity.pojo.ImportRecordMsgDO;
import com.bestcem.xm.member.enums.ImportRecordStatusEnum;
import com.bestcem.xm.member.enums.MemberTypeEnum;
import com.bestcem.xm.member.grpc.service.param.imports.*;
import com.bestcem.xm.member.handler.MemberImportProgressHandler;
import com.bestcem.xm.member.handler.imports.*;
import com.bestcem.xm.member.service.ConvertUtil;
import com.bestcem.xm.member.service.ImportService;
import com.bestcem.xm.member.service.dto.ImportRecordDTO;
import com.bestcem.xm.member.service.dto.PageDTO;
import com.bestcem.xm.member.service.param.ImportMemberParam;
import com.bestcem.xm.member.service.param.ImportProjectParam;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.bestcem.xm.member.constant.Constants.PROGRESS_BAR_OPERATION_MAP;

/**
 * 导入
 *
 * @author yf.wang <yf.wang@idiaoyan.com>
 * @version V1.0
 * @date 2021/7/20
 */
@Service
public class ImportServiceImpl implements ImportService {

    @Resource
    private RedisService redisService;

    @Resource
    private ImportRecordDao importRecordDao;

    @Resource
    private IndividualMemberImportHandler individualMemberImportHandler;

    @Resource
    private InstitutionMemberImportHandler institutionMemberImportHandler;

    @Resource
    private InteriorMemberImportHandler interiorMemberImportHandler;

    @Resource
    private ProjectImportHandler projectImportHandler;

    @Resource
    private MemberImportProgressHandler memberImportProgressHandler;

    @Override
    public ServiceResult<String> downLoadTemplate(DownLoadTemplateParam param) {
        switch (param.getTemplateName()) {
            case "个人联系人导入模板":
                return individualMemberImportHandler.downTemplate(param.getOrgId());
            case "机构联系人导入模板":
                return institutionMemberImportHandler.downTemplate(param.getOrgId());
            case "内部联系人导入模板":
                return interiorMemberImportHandler.downTemplate(param.getOrgId());
            case "企业项目导入模板":
                return projectImportHandler.downTemplate(param.getOrgId());
            default:
                return ServiceResult.fail("模板名称错误");
        }
    }

    @Override
    public ServiceResult<String> checkImport(CheckImportParam param) {
        BaseImportHandle baseImportHandle = null;
        String id = null;
        String key = null;
        Object result = null;
        switch (EnumUtil.getEnumByIndex(MemberTypeEnum.class, param.getAttribute())) {
            case INDIVIDUAL:
                baseImportHandle = new IndividualMemberImportHandler();
                key = baseImportHandle.genImportLockKey(param.getOrgId());
                result = redisService.get(key);
                id = ObjectUtil.isEmpty(result) ? "" : String.valueOf(result);
                return ServiceResult.success(id);
            case INSTITUTION:
                key = institutionMemberImportHandler.genImportLockKey(param.getOrgId());
                result = redisService.get(key);
                id = ObjectUtil.isEmpty(result) ? "" : String.valueOf(result);
                return ServiceResult.success(id);
            case HIDDEN:
                baseImportHandle = new InteriorMemberImportHandler();
                key = baseImportHandle.genImportLockKey(param.getOrgId());
                result = redisService.get(key);
                id = ObjectUtil.isEmpty(result) ? "" : String.valueOf(result);
                return ServiceResult.success(id);
            default:
                return ServiceResult.fail("invalid mtype");
        }
    }

    @Override
    public XmResultJson checkImport(Integer mType, String orgId) {
        BaseImportHandle baseImportHandle = null;
        String id = null;
        String key = null;
        Object result;
        JSONObject resultObj = new JSONObject();
        switch (EnumUtil.getEnumByIndex(MemberTypeEnum.class, mType)) {
            case INDIVIDUAL:
                key = individualMemberImportHandler.genImportLockKey(orgId);
                result = redisService.get(key);
                id = ObjectUtil.isEmpty(result) ? "" : String.valueOf(result);
                resultObj.put("record_id", id);
                return XmResultJson.success(resultObj);
            case INSTITUTION:
                key = institutionMemberImportHandler.genImportLockKey(orgId);
                result = redisService.get(key);
                id = ObjectUtil.isEmpty(result) ? "" : String.valueOf(result);
                resultObj.put("record_id", id);
                return XmResultJson.success(resultObj);
            case INTERIOR:
                key = interiorMemberImportHandler.genImportLockKey(orgId);
                result = redisService.get(key);
                id = ObjectUtil.isEmpty(result) ? "" : String.valueOf(result);
                resultObj.put("record_id", id);
                return XmResultJson.success(resultObj);
            case PROJECT:
                key = projectImportHandler.genImportLockKey(orgId);
                result = redisService.get(key);
                id = ObjectUtil.isEmpty(result) ? "" : String.valueOf(result);
                resultObj.put("record_id", id);
                return XmResultJson.success(resultObj);
            default:
                return XmResultJson.fail(AppRequestErrorCode.PARAM_LOST, "invalid mtype");
        }
    }

    @Override
    public ServiceResult<PageDTO> listImportRecords(ListImportRecordsParam param) {
//        List<Integer> attributes = new ArrayList<>();
//        // 如果是机构联系人
//        if (param.getAttribute() == MemberTypeEnum.INSTITUTION.getIndex()) {
//            attributes.add(MemberTypeEnum.INTERIOR.getIndex());
//            attributes.add(MemberTypeEnum.PROJECT.getIndex());
//        } else {
//            attributes.add(param.getAttribute());
//        }
//        // 获取总页数
//        Long count = importRecordDao.countByOrgIdAndAttributeInAndSort(param.getOrgId(), param.getUserId(), attributes);
//        // 获取数据
//        List<ImportRecord> importRecords =
//                importRecordDao.findPageByOrgIdAndAttributeInAndSort(param.getPageParam(),
//                        param.getOrgId(), param.getUserId(), attributes, param.getSorts());
//        List<ImportRecordDTO> importRecordDTOS = new ArrayList<>();
//        if (CollectionUtil.isNotEmpty(importRecords)) {
//            importRecords.forEach(importRecord -> {
//                ImportRecordDTO dto = new ImportRecordDTO();
//                BeanUtil.copyProperties(importRecord, dto, false);
//                JSONObject data = importRecord.getData();
//                if (ObjectUtil.isNotEmpty(data)) {
//                    Integer failedCount = data.getIntValue("failedCount");
//                    if (failedCount >= 1) {
//                        dto.setPartialSuccess(Boolean.TRUE);
//                    }
//                }
//                dto.setPartialSuccess(Boolean.FALSE);
//                importRecordDTOS.add(dto);
//            });
//        }
//        return ServiceResult.success(new PageDTO(importRecordDTOS, count.intValue()));
        return null;
    }

    @Override
    public XmResultJson listImportRecords(HttpGetImportRecordParam query) {
        List<Integer> attributes = new ArrayList<>();
        // 如果是机构联系人 则获取 机构联系人和项目的导入记录
        if (query.getMtype() == MemberTypeEnum.INSTITUTION.getIndex()) {
            attributes.add(MemberTypeEnum.INSTITUTION.getIndex());
            attributes.add(MemberTypeEnum.PROJECT.getIndex());
        } else {
            attributes.add(query.getMtype());
        }
        // 获取总页数
        Long count = importRecordDao.countByOrgIdAndUserIdAndAttributeIn(query.getOrgId(), query.getUserId(), attributes);

        // 获取记录
        int start = PageUtil.getStart(query.getPage() - 1, query.getRowsPerPage());
        List<ImportRecordDo> importRecordEntities =
                importRecordDao.findPageByOrgIdAndUserIdAndAttributeIn(query.getOrgId(), query.getUserId(), attributes, start, query.getRowsPerPage());

        List<HttpImportRecordDTO> importRecordDTOS = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(importRecordEntities)) {
            importRecordEntities.forEach(importRecordDo -> {
                // 类型转换
                HttpImportRecordDTO dto = ConvertUtil.importRecordDoToHttpImportRecordDTO(importRecordDo);
                Integer failedCount = importRecordDo.getFailedCount();
                if (ObjectUtil.isNotEmpty(failedCount)) {
                    if (failedCount >= 1) {
                        // 若存在失败条数 则为true 前端可以展示失败记录
                        dto.setPartialSuccess(Boolean.TRUE);
                    } else {
                        dto.setPartialSuccess(Boolean.FALSE);
                    }
                } else {
                    dto.setPartialSuccess(Boolean.FALSE);
                }
                importRecordDTOS.add(dto);
            });
        }
        return XmResultJson.success(new PageDTO(importRecordDTOS, count.intValue()));
    }

    @Override
    public ServiceResult<Float> getImportProgress(GetImportProgressParam param) {
        String importProgressKey = "member:member.import." + param.getId();
        Object result = redisService.get(importProgressKey);
        float percent = 0.0f;
        if (ObjectUtil.isEmpty(result)) {
            // 没有相关key
            // 查询记录
            ImportRecordDo importRecordEntity = importRecordDao.findOneById(param.getId());
            if (ObjectUtil.isNotEmpty(importRecordEntity)) {
                Integer status = importRecordEntity.getStatus();
                if (status == ImportRecordStatusEnum.IMPORT_RECORD_STATUS_SUCCESS.getIndex() ||
                        status == ImportRecordStatusEnum.IMPORT_RECORD_STATUS_FAILED.getIndex()) {
                    percent = 1.0f;
                } else {
                    String key = null;
                    // 判断是否有正在导入的任务
                    switch (EnumUtil.getEnumByIndex(MemberTypeEnum.class, param.getAttribute())) {
                        case INDIVIDUAL:
                            key = new IndividualMemberImportHandler().genImportLockKey(param.getOrgId());
                            break;
                        case INSTITUTION:
                            key = new InstitutionMemberImportHandler().genImportLockKey(param.getOrgId());
                            break;
                        case INTERIOR:
                            key = new InteriorMemberImportHandler().genImportLockKey(param.getOrgId());
                            break;
                        default:
                            key = "";
                    }
                    if (redisService.hasKey(key)) {
                        percent = 0.0f;
                    } else {
                        percent = 1.0f;
                    }
                }
            } else {
                return ServiceResult.fail("该记录不存在");
            }
        } else {
            // 有相关key
            JSONObject object = JSONObject.parseObject(String.valueOf(result));
            Float completeCount = object.getFloat("complete_count");
            Float totalCount = object.getFloat("total_count");
            Long lastTimestamp = object.getLong("last_timestamp");
            if (System.currentTimeMillis() - lastTimestamp > 3600) {
                // 上次更新数据的状态超过3600s 则设置状态为导入超时
                String totalErrorMsg = new JSONObject().put("-1", "导入失败").toString();
                // 更新导入记录状态为导入失败
                importRecordDao.updateRecordStatus(param.getId(), ImportRecordStatusEnum.IMPORT_RECORD_STATUS_FAILED.getIndex());
                percent = 1.0f;
            } else {
                if (totalCount == 0) {
                    percent = 1.0f;
                } else {
                    percent = completeCount / totalCount;
                }
            }
        }
        return ServiceResult.success(percent);
    }

    @Override
    public XmResultJson getImportProgress(GetImportProgressQuery query) {
        HttpRecordProgressDTO dto = new HttpRecordProgressDTO();
        List<String> ids = query.getId();
        for (int i = 0; i < ids.size(); i++) {
            List<Double> percent = new ArrayList<>();
            String id = ids.get(i);
            // 根据导入记录id获取当前进度
            Double progress = memberImportProgressHandler.getProgress(id, 0, query.getAttribute(), query.getOrgId());
            if (ObjectUtil.isEmpty(progress)) {
                return XmResultJson.fail(AppResourceErrorCode.NOT_FOUND, "id 资源不存在");
            }
            percent.add(progress);
            dto.setPercent(percent);
        }

        return XmResultJson.success(dto);
    }

    @Override
    public ServiceResult<PageDTO> listImportDetails(ListImportDetailsParam param) {
//        // 判断是否存在
//        Integer count = importRecordDao.countTotalErrorMsg(param.getId());
//        if (count == 0) {
//            return ServiceResult.success(new PageDTO(List.of(), 0));
//        }
//        int start = PageUtil.getStart(param.getPageParam().getPage() - 1, param.getPageParam().getSize());
//        // 获取错误记录
//        ImportRecordDetailDTO importRecordDetailDTO =
//                importRecordDao.findTotalErrorMsgPageById(param.getId(), start, param.getPageParam().getSize());
//        List<ImportRecordDetailDTO> details = new ArrayList<>();
//        if (ObjectUtil.isNotEmpty(importRecordDetailDTO)) {
//            List<String> totalErrorMsgs = importRecordDetailDTO.getTotalErrorMsg();
//            // 解析
//            if (CollectionUtil.isNotEmpty(totalErrorMsgs)) {
//                totalErrorMsgs.forEach(errorMsg -> {
//                    // {"-1": "导入失败"}
//                    JSONObject errorMsgJson = JSONObject.parseObject(errorMsg);
//                    Set<String> keys = errorMsgJson.keySet();
//                    // 确定只有一个key
//                    keys.forEach(key -> {
//                        ImportRecordDetailDTO detailDTO = new ImportRecordDetailDTO();
//                        detailDTO.setLine(Integer.parseInt(key));
//                        detailDTO.setDesc(errorMsgJson.getString(key));
//                        details.add(detailDTO);
//                    });
//                });
//            }
//        }
//        return ServiceResult.success(new PageDTO(details, count));
        return null;
    }

    @Override
    public XmResultJson listImportDetails(String recordId, String orgId, Integer page, Integer rowsPerPage) {
        // 获取当前记录 错误的条数
        Integer count = importRecordDao.countTotalErrorMsg(recordId);
        if (count == 0) {
            return XmResultJson.success(new PageDTO(new ArrayList(), 0));
        }
        int start = PageUtil.getStart(page - 1, rowsPerPage);
        // 获取错误记录
        List<ImportRecordMsgDO> importRecordMsgEntity =
                importRecordDao.findTotalErrorMsgPageById(recordId, start, rowsPerPage);
        List<HttpImportRecordDetailDTO> details = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(importRecordMsgEntity)) {
            // 解析
            importRecordMsgEntity.forEach(errorMsg -> {
                HttpImportRecordDetailDTO detailDTO = new HttpImportRecordDetailDTO();
                detailDTO.setLine(errorMsg.getLine().toString());
                detailDTO.setDesc(errorMsg.getMessage());
                details.add(detailDTO);
            });
        }
        return XmResultJson.success(new PageDTO(details, count));
    }

    @Override
    public ServiceResult<ImportRecordDTO> getImportRecord(GetImportRecordParam param) {
//        ImportRecord importRecord = importRecordDao.findOneById(param.getId());
//        if (ObjectUtil.isEmpty(importRecord)) {
//            return ServiceResult.fail("该记录不存在");
//        }
//        ImportRecordDTO dto = new ImportRecordDTO();
//        BeanUtil.copyProperties(importRecord, dto, false);
//        JSONObject data = importRecord.getData();
//        if (ObjectUtil.isNotEmpty(data)) {
//            Integer failedCount = data.getInteger("failedCount");
//            if (failedCount >= 1) {
//                dto.setPartialSuccess(Boolean.TRUE);
//            }
//        }
//        dto.setPartialSuccess(Boolean.FALSE);
//        return ServiceResult.success(dto);
        return null;
    }

    @Override
    public XmResultJson getImportRecord(String orgId, String id) {
        ImportRecordDo importRecordEntity = importRecordDao.findOneById(id);
        if (ObjectUtil.isEmpty(importRecordEntity)) {
            return XmResultJson.fail(AppResourceErrorCode.NOT_FOUND, StrUtil.format("ImportRecord[id={}] not found", id));
        }
        HttpImportRecordDTO dto = ConvertUtil.importRecordDoToHttpImportRecordDTO(importRecordEntity);
        Integer failedCount = importRecordEntity.getFailedCount();
        // 判断是 成功 还是 部分成功
        if (ObjectUtil.isNotEmpty(failedCount)) {
            if (failedCount >= 1) {
                dto.setPartialSuccess(Boolean.TRUE);
            } else {
                dto.setPartialSuccess(Boolean.FALSE);
            }
        } else {
            dto.setPartialSuccess(Boolean.FALSE);
        }
        return XmResultJson.success(dto);
    }

    @Override
    public ServiceResult<String> importMembers(ImportMembersParam param) {
        switch (EnumUtil.getEnumByIndex(MemberTypeEnum.class, param.getAttribute())) {
            case INDIVIDUAL:
                return individualMemberImportHandler.ImportMember(param);
            case INSTITUTION:
                return institutionMemberImportHandler.ImportMember(param);
            case HIDDEN:
                return interiorMemberImportHandler.ImportMember(param);
            default:
                return ServiceResult.fail("invalid mtype");
        }
    }

    @Override
    public ServiceResult<String> importMembers(ImportMemberParam param) {
        // 根据联系人类型执行不同的方法
        switch (EnumUtil.getEnumByIndex(MemberTypeEnum.class, param.getAttribute())) {
            case INDIVIDUAL:
                // 个人联系人
                return individualMemberImportHandler.ImportMember(param);
            case INSTITUTION:
                // 机构联系人
                return institutionMemberImportHandler.ImportMember(param);
            case INTERIOR:
                // 内部联系人
                return interiorMemberImportHandler.ImportMember(param);
            default:
                return ServiceResult.fail("invalid mtype");
        }
    }

    @Override
    public ServiceResult<String> importProjects(ImportProjectParam param) {
        // 导入项目
        return projectImportHandler.importProject(param);
    }

    @Override
    public void setProgressBarStatus(int type, String recordId, Integer completeCount, Integer count) {
        String key = PROGRESS_BAR_OPERATION_MAP.get(type) + recordId;
        JSONObject valueJson = new JSONObject();
        valueJson.put("complete_count", completeCount);
        valueJson.put("total_count", count);
        valueJson.put("last_timestamp", System.currentTimeMillis());
        redisService.set(key, valueJson.toString(), 3600, TimeUnit.SECONDS);
    }

    @Override
    public void deleteProgressBarStatus(int type, String recordId) {
        String key = PROGRESS_BAR_OPERATION_MAP.get(type) + recordId;
        redisService.del(key);
    }

    /**
     * 计算更新进度步长
     *
     * @param totalCount
     * @return
     */
    @Override
    public Integer getCalcUpdateProgressStep(Integer totalCount) {
        // 同步更新进度步长 5% 更新一次
        Integer per = ((int) (totalCount * 0.05));
        return per > 50 ? per : 50;
    }

    @Override
    public void updateImportRecordErrorMessage(String seq, String message, String recordId, int status) {
        JSONObject errorMsgJson = new JSONObject();
        errorMsgJson.put(seq, message);
        JSONArray errorArray = new JSONArray();
        errorArray.add(errorMsgJson);
        Integer receiveCount = 0;
        Integer successCount = 0;
        Integer failedCount = 0;
        importRecordDao.updateImportRecordData(recordId, receiveCount, successCount, failedCount, errorArray, status);
    }

    @Override
    public void updateImportRecordData(String recordId, JSONObject dataJson, int status) {
        Integer receiveCount = dataJson.getInteger("receiveCount");
        Integer successCount = dataJson.getInteger("successCount");
        Integer failedCount = dataJson.getInteger("failedCount");
        JSONArray data = dataJson.getJSONArray("total_error_msg");
        importRecordDao.updateImportRecordData(recordId, receiveCount, successCount, failedCount, data, status);
    }
}
